package com.darren.framework.shiro;


import com.darren.archive.entity.LoginRecord;
import com.darren.archive.service.LoginRecordService;
import com.darren.framework.Exception.TokenException;
import com.darren.framework.entity.TokenEntity;
import com.darren.framework.utils.Constant;
import com.darren.framework.utils.JWTUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class MyStatelessShiroFilter extends AccessControlFilter {

    protected Logger logger = LogManager.getLogger(getClass());

    @Autowired
    private LoginRecordService loginRecordService;

    /**
     * 返回false
     *
     * @param servletRequest
     * @param servletResponse
     * @param mappedValue
     * @return 返回结果是false的时候才会执行下面的onAccessDenied方法
     * @throws Exception
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object mappedValue) throws Exception {
        logger.info("is access allowed");
        return false;
    }

    /**
     * 从请求头获取token并验证，验证通过后交给realm进行登录
     *
     * @param servletRequest
     * @param servletResponse
     * @return 返回结果为true表明登录通过
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        logger.info("on access denied");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String token = request.getHeader(Constant.ACCESS_TOKEN);
        try {
                TokenEntity tokenEntity = JWTUtil.unSignAccessJWT(token, TokenEntity.class);
            LoginRecord loginRecord = loginRecordService.findById(tokenEntity.getId());
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(loginRecord.getUserAccount(), loginRecord.getUserAccount());
            //委托realm进行登录认证
            getSubject(servletRequest, servletResponse).login(usernamePasswordToken);
            return true;
        } catch (TokenException tokenException) {//token 检验异常
            // 过滤器中的异常，不会被全局异常统一处理器捕获，所以将异常放到request中，
            // 再跳转到 /filter/exception，重新抛出，全局异常统一处理器就能捕获到，做统一处理了
            servletRequest.setAttribute("exception", tokenException);
            request.getRequestDispatcher("/filter/exception").forward(servletRequest, servletResponse);//跳转
        } catch (Exception exception) {
            logger.error(exception.getMessage(), exception);
        }
        redirectToLogin(servletRequest, servletResponse);
        return false;
    }

    /**
     * 重定向到登录页
     *
     * @param request
     * @param response
     * @throws IOException
     */
    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        logger.info("redirectToLogin");
        WebUtils.issueRedirect(request, response, "/login");
    }

}
